/***************************************************************************\
 * The Mattise Kernel														*
 * Copyright 2007 Matthew Iselin											*
 * Licensed under the GPL													*
 *																			*
 * newio.c																	*
 *																			*
 * New, message-based I/O system											*
 *																			*
\***************************************************************************/

// Includes
#include <sys/stat.h>
#include "mmsg.h"
#include "newio.h"
#include <vfs.h>

// Functions

// Opens a file
int new_open( const char* file, int flags, int mode )
{
	// send out a message
	struct vfs_Action* msg = (struct vfs_Action*) mattiseAllocMessageSz( sizeof( struct vfs_Action ) ); // malloc( sizeof( struct vfs_Action ) );
	
	// fill in the action
	msg->msgcode = VFS_OPEN;
	msg->nmlen = sprintf( msg->filenm, "%s", file );
	msg->vfsArg1 = mode; // mode
	msg->vfsArg2 = flags; // flags
	msg->vfsArg3 = getpid(); // sender process
	
	// send it out
	mattiseSendMessage( 1, VFS_OPEN, (char*) msg, sizeof( struct vfs_Action ) );
	
	// wait for a reply
	struct RecvMsgData myMsg;
	while( !mattiseHasMessage() );
	
	// get the message
	char* mbuff = mattiseRecvMessage( &myMsg );
	
	// get the reply
	struct vfs_ReqData reply = *((struct vfs_ReqData*) mbuff);
	
	// return value (before freeing)
	int ret = reply.descriptor;
	
	// free the message buffer
	mattiseFreeMessage( mbuff );
	
	// return the length of data written
	return ret;
}

// Gets statistics on an open file
int new_fstat( int file, struct stat* st )
{
	// check for a valid descriptor
	if( file == -1 )
		return -1;
	
	// if it's stdin/stdout/stderr then we just say it's a character device
	if( file < 3 )
	{
		st->st_mode = S_IFCHR;
		return 0;
	}
	
	// send out a message
	struct vfs_ReqData* msg = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) ); // malloc( sizeof( struct vfs_ReqData ) );
	
	// pass it on
	msg->msgcode = VFS_STAT;
	msg->descriptor = file;
	msg->datlen = 0;
	msg->srcpid = getpid();

	// send it out
	mattiseSendMessage( file, VFS_STAT, (char*) msg, sizeof( struct vfs_ReqData ) );
	
	// wait for a reply
	struct RecvMsgData myMsg;
	while( !mattiseHasMessage() );
	
	// get the message
	char* mbuff = mattiseRecvMessage( &myMsg );
	
	// get the reply
	struct vfs_ReqData reply = *((struct vfs_ReqData*) mbuff);
	
	// free the message buffer
	mattiseFreeMessage( mbuff );
	
	// fill in our data
	memcpy( st, reply.data, sizeof( struct stat ) );
	
	// success
	return 0;
}

// Reads from a file
int new_read( int fd, char* dat, int len )
{
	// check for valid length
	if( len > 0x500 || fd == -1 )
		return -1;
	
	// send out a message
	struct vfs_ReqData* msg = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) );
	
	// pass it on
	msg->msgcode = VFS_READ;
	msg->descriptor = fd;
	msg->datlen = len;
	msg->srcpid = getpid();

	// send it out
	mattiseSendMessage( fd, VFS_READ, (char*) msg, sizeof( struct vfs_ReqData ) );
	
	// wait for a reply
	struct RecvMsgData myMsg;
	while( !mattiseHasMessage() );
	
	// get the message
	char* mbuff = mattiseRecvMessage( &myMsg );
	
	// get the reply
	struct vfs_ReqData reply = *((struct vfs_ReqData*) mbuff);
	
	// fill in our data
	if( reply.datlen != 0 && reply.datlen != -1 )
		memcpy( dat, reply.data, reply.datlen );
	
	// return value (before freeing)
	int ret = reply.datlen;
	
	// free the message buffer
	mattiseFreeMessage( mbuff );
	
	// return the length of data written
	return ret;
}

// Writes to a file
int new_write( int fd, char* buff, int len )
{
	// check for valid length
	if( len > 0x500 || fd == -1 )
		return -1;
	
	// send out a message
	struct vfs_ReqData* msg = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) ); // malloc( sizeof( struct vfs_ReqData ) );
	
	// pass it on
	msg->msgcode = VFS_WRITE;
	msg->descriptor = fd;
	msg->datlen = len;
	memcpy( msg->data, buff, len );
	msg->srcpid = getpid();
	
	// send it out
	mattiseSendMessage( fd, VFS_WRITE, (char*) msg, sizeof( struct vfs_ReqData ) );
	
	// wait for a reply
	struct RecvMsgData myMsg;
	while( !mattiseHasMessage() );
	
	// get the message
	char* mbuff = mattiseRecvMessage( &myMsg );
	
	// get the reply
	struct vfs_ReqData reply = *((struct vfs_ReqData*) mbuff);
	
	// return value (before freeing)
	int ret = reply.datlen;
	
	// free the message buffer
	mattiseFreeMessage( mbuff );
	
	// return the length of data written
	return ret;
}

// Seeks to a new location in a file
int new_seek( int fd, int loc, int whence )
{
	// check for a valid descriptor
	if( fd == -1 )
		return -1;
	
	// send out a message
	struct vfs_ReqData* msg = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) ); // malloc( sizeof( struct vfs_ReqData ) );
	
	// pass it on
	msg->msgcode = VFS_SEEK;
	msg->descriptor = fd;
	msg->srcpid = getpid();
	msg->reqArg1 = loc;
	msg->reqArg2 = whence;
	
	// send it out
	mattiseSendMessage( fd, VFS_SEEK, (char*) msg, sizeof( struct vfs_ReqData ) );
	
	// wait for a reply
	struct RecvMsgData myMsg;
	while( !mattiseHasMessage() );
	
	// get the message
	char* mbuff = mattiseRecvMessage( &myMsg );
	
	// get the reply
	struct vfs_ReqData reply = *((struct vfs_ReqData*) mbuff);
	
	// return value (before freeing)
	int ret = reply.reqArg1;
	
	// free the message buffer
	mattiseFreeMessage( mbuff );
	
	// return the new location
	return ret;
}

// Closes a file
int new_close( int fd )
{
	// check for a valid descriptor
	if( fd == -1 )
		return -1;
		
	// send out a message
	struct vfs_ReqData* msg = (struct vfs_ReqData*) mattiseAllocMessageSz( sizeof( struct vfs_ReqData ) ); // malloc( sizeof( struct vfs_ReqData ) );
	
	// pass it on
	msg->msgcode = VFS_CLOSE;
	msg->descriptor = fd;
	msg->srcpid = getpid();
	
	// send it out
	mattiseSendMessage( fd, VFS_CLOSE, (char*) msg, sizeof( struct vfs_ReqData ) );

	// return success
	return 0;
}
